package top.laoshuzi.cloudplatform.network;

import io.netty.buffer.Unpooled;
import top.laoshuzi.cloudplatform.servo.ServoHandler;
import top.laoshuzi.cloudplatform.servo.bean.ServoControlBean;
import top.laoshuzi.cloudplatform.servo.util.ServoProtocol;
import top.laoshuzi.cloudplatform.tools.L;
import top.laoshuzi.photinia.base.NetworkExecutor;
import top.laoshuzi.photinia.Photinia;
import top.laoshuzi.photinia.base.ResponseExecutor;
import io.netty.channel.Channel;
import top.laoshuzi.photinia.error.ParseError;
import top.laoshuzi.photinia.rest.binder.IBinder;
import top.laoshuzi.photinia.rest.net.BasicNetwork;
import top.laoshuzi.photinia.rest.net.Network;
import top.laoshuzi.photinia.rest.net.NetworkFactory;
import top.laoshuzi.photinia.rest.net.NetworkManager;
import top.laoshuzi.photinia.rest.protocol.Answer;
import top.laoshuzi.photinia.rest.protocol.FrameParcel;
import top.laoshuzi.photinia.rest.protocol.PhotiniaProtocol;
import top.laoshuzi.photinia.rest.protocol.Recv;
import top.laoshuzi.photinia.rest.protocol.Send;
import top.laoshuzi.photinia.rest.protocol.base.HeaderParser;
import top.laoshuzi.photinia.rest.protocol.impl.RestAnswer;

import java.io.IOException;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Mouse on 2017/11/8.
 */
public class SimpleServer {

    private final IBinder binder;
    private final Map<Network, NetworkExecutor> executors = new ConcurrentHashMap<>();
    private final Map<String, GroupDeal> groupDealMap = new HashMap<>();

    public SimpleServer() {
        binder = Photinia.newPersistentBinder(new NetworkFactory() {
            @Override
            public Network createNetwork(Channel channel) {
                return new BasicNetwork(channel);
            }
        });
        initNetwork();
    }

    public void bind(SocketAddress address) {
        binder.bind(address);
    }

    public void shutdown() {
        binder.shutdownGracefully();
    }

    private void initNetwork() {
        binder.getNetworkManager().addNetworkListener(new NetworkManager.NetworkListener() {
            @Override
            public void onCreated(Network network) {
                NetworkExecutor executor = new NetworkExecutor(network);
                executor.setResponseTaskListener(new ResponseExecutor.ResponseTaskListener() {
                    @Override
                    public void requestHandler(Network network, Recv recv) {

                        try {
                            //解析组
                            String group = HeaderParser.STRING_PARSER.parse(recv.headers(), SimpleProtocol.GROUP);

                            //响应
                            Answer answer = new RestAnswer(recv);
                            groupDealMap.get(group).deal(recv, answer.send());
                            L.d("发送-->>响应");
                            network.send(answer.send());

                        } catch (ParseError parseError) {
                            parseError.printStackTrace();
                        }
                    }
                });
                executors.put(network, executor);
            }

            @Override
            public void onDestroy(Network network) {
                NetworkExecutor executor = executors.get(network);
                if (executor != null) {
                    executor.close();
                }
            }
        });

        //舵机
        groupDealMap.put(ServoProtocol.NAME, new GroupDeal() {
            @Override
            public void deal(Recv recv, Send send) {

                try {
                    //解析动作
                    String action = HeaderParser.STRING_PARSER.parse(recv.headers(), SimpleProtocol.ACTION);

                    //控制舵机动作
                    if (action.equals(ServoProtocol.ServoControl.NAME)) {
                        ServoControlBean servoControlBean = new ServoControlBean(new FrameParcel(recv.body()));

                        for (ServoControlBean.ControlBean controlBean : servoControlBean.getControlBeans()) {
                            try {
                                switch (controlBean.getCode()) {
                                    case ServoProtocol.ServoControl.ControlCode.HORIZONTAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.INCREASE_ANGLE:
                                        //控制舵机水平增加角度
                                        ServoHandler.getInstance().increaseHorizontalServoAngle(controlBean.getAngle());
                                        break;
                                    case ServoProtocol.ServoControl.ControlCode.HORIZONTAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.DECREASE_ANGLE:
                                        //控制舵机水平减少角度
                                        ServoHandler.getInstance().decreaseHorizontalServoAngle(controlBean.getAngle());
                                        break;
                                    case ServoProtocol.ServoControl.ControlCode.HORIZONTAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.SET_ANGLE:
                                        //控制舵机水平设置角度
                                        ServoHandler.getInstance().setHorizontalServoAngle(controlBean.getAngle());
                                        break;
                                    case ServoProtocol.ServoControl.ControlCode.VERTICAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.INCREASE_ANGLE:
                                        //控制舵机竖直增加角度
                                        ServoHandler.getInstance().increaseVerticalServoAngle(controlBean.getAngle());
                                        break;
                                    case ServoProtocol.ServoControl.ControlCode.VERTICAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.DECREASE_ANGLE:
                                        //控制舵机竖直减少角度
                                        ServoHandler.getInstance().decreaseVerticalServoAngle(controlBean.getAngle());
                                        break;
                                    case ServoProtocol.ServoControl.ControlCode.VERTICAL_MOVE
                                            | ServoProtocol.ServoControl.ControlCode.SET_ANGLE:
                                        //控制舵机竖直设置角度
                                        ServoHandler.getInstance().setVerticalServoAngle(controlBean.getAngle());
                                        break;
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    send.addHeader("group",
                            Unpooled.wrappedBuffer(ServoProtocol.NAME.getBytes(PhotiniaProtocol.charset))
                    );
                    send.addHeader("action",
                            Unpooled.wrappedBuffer(ServoProtocol.NAME.getBytes(PhotiniaProtocol.charset))
                    );
                    send.body(Unpooled.wrappedBuffer(new byte[1]));
                } catch (ParseError parseError) {
                    parseError.printStackTrace();
                }

            }
        });
    }


    interface GroupDeal {

        void deal(Recv recv, Send send);
    }


}
